Google Data Analytics Professional Capstone Project - BellaBeat

Bellabeat, a high-tech manufacturer of health-focused products for women. In order to answer the key business questions, I followed the steps of the data analysis process: ask, prepare, process, analyze, share, and act.

I acted as a junior data analyst working on the marketing analyst team at Bellabeat. The Chief Creative Officer of Bellabeat, believes that analyzing smart device fitness data could help unlock new growth opportunities for the company. As part of the data analytics team, I have been asked to focus on one of Bellabeat’s products and analyze smart device data to gain insight into how consumers are using their smart devices. The insights I discover will then help guide marketing strategy for the company. I will present your analysis to the Bellabeat executive team along with your high-level recommendations for Bellabeat’s marketing strategy. Analysis of Bellabeat’s available consumer data would reveal more opportunities for growth. The analysis is to focus on a Bellabeat product and analyze smart device usage data in order to gain insight into how people are already using their smart devices. Then, using this information, make high-level recommendations for how these trends can inform Bellabeat marketing strategy.

Step 1: Ask

In my hypothetical role as the Junior data analyst for Bellabeat’s marketing team, the CCO asks me to analyze smart device usage data in order to gain insight into how consumers use non-Bellabeat smart devices. She then wants me to select one Bellabeat product to apply these insights to in your presentation. These questions guided my analysis:

  1. What are some trends in smart device usage?
  1. How could these trends apply to Bellabeat customers?
  1. How could these trends help influence Bellabeat marketing strategy?

As part of the ask process of data analysis, I identified the key task of the analysis and the stakeholders who I would make recommendations based on the insights derived from the data.

Key tasks

1. Identify the business task : The main business task is to use the smart devices data to analyse how users are using smart devices to monitor their activity.

2. Consider key stakeholders : the main stakeholders of the analysis are the executive team which comprises of the CCO &co-founders,the customer facing team who are the marketing team, and the analytics team who are carrying out the analysis.

Deliverable:  A clear statement of the business task

The main deliverable of the Ask Phase is a clear business task which I documented as below:

Bellabeat would like to identify the usage of lifestyle lifestyle smart devices by users. In order to do so, we will analyse the data collected from smart devices users who do not use BellaBeat to identify trends of how they use smart devices. This will help influence the marketing strategy of BellaBeat to advertise their products to more users.

Step 2: Prepare

The CCO encourages the use public data that explores smart device users’ daily habits. She points us to a specific data set:

FitBit Fitness Tracker Data (CC0:Public Domain, dataset made available through Mobius): This Kaggle data set contains personal fitness tracker from thirty fitbit users. Thirty eligible Fitbit users consented to the submission of personal tracker data, including minute-level output for physical activity, heart rate, and sleep monitoring. It includes information about daily activity, steps, and heart rate that can be used to explore users’ habits.

The CCO tells us that this data set might have some limitations, and encourages us to consider adding another data to help address those limitations as you begin to work more with this data.

The guiding questions in the preparation of the data are as below:

Where is your data stored?

The data is stored on Kaggle as part of the FitBit Fitness Tracker dataset made available through Mobius. The data set contains personal fitness tracker from thirty fitbit users who consented the collection of their personal tracker data including minute-level output for physical activity, heart rate, and sleep monitoring. It includes information about daily activity, steps, and heart rate that can be used to explore users’habits.

How is the data organized? Is it in long or wide format?

The data is stored in csv files which are organised in terms of minute, hourly and daily measurements of calories intake, steps, sleep and activity intensity.

Are there issues with bias or credibility in this data? Does your data ROCCC?

To access the credibility of the data, I followed the ROCCC criteria by Google. For each of the datasets I determined if the data is:

  1. Reliable: The dataset is reliable for the analysis as it contains fitness data relating to sleep, steps taken, calory intake and heart rate. The data helps us to get insights into the use of fitbits by users.
  2. Original: Data was collected by fitness tracker users.
  3. Comprehensive: Data was organised in according to minute, hour and daily measurements hence it was easy to understand.
  4. Current: Dataset comprised of user activity for the 12 months in 2016 which is current.
  5. Cited: The data is not cited, it is however available on Kaggle.

How are you addressing licensing, privacy, security, and accessibility?

The data was anonymised with no PII included in the data. The data was classified using a unique ID that was used to link the different datasets.

How did you verify the data’s integrity?

The data can be said to have integrity as it is publicly available on Kaggle which is a public platform for data. To check the dataset integrity, I confirmed the entity and referential integrity of the data. The data had unique Ids that correlated to the users who submitted the data. The unique Id was consistent throughout all the datasets.

How does it help you answer your question?

The dataset contains information collected by 30 fitbit users over two months. This data will help me identify the trends in the use of fitbit trackers hence answering the questions in the business task.

● Are there any problems with the data?

The data has date columns that is stored as a string. In order to properly analyse the data, I changed all date columns into the datetime format in R using the POSIX function.

Step 3: Process

The process phase is to ensure the data is complete and can be used in the analyze phase. In order to process the data, I used the following guiding questions:

Guiding questions

What tools are you choosing and why?

R: I am using R due to its capabilities in data cleaning, joining the datasets and visualize the data to get key insights to solve the business task.

Have you ensured your data’s integrity?

I ensured that the data had entity and referential integrity by confirming all user Ids were consistent in all datasets.

What steps have you taken to ensure that your data is clean?

To ensure my data is clean, I followed the below steps:

1) Removed duplicate rows

2) Removed rows that have null columns

3) Ensured the datetime columns are properly formatted.

● How can you verify that your data is clean and ready to analyze? To verify that the data was correct to use, analysed the datasets’ summary statistics in R. This will show if there are any nulls in the data, identify the mean, min, max and avg of numerical variables to get a highlight of the data.

● Have you documented your cleaning process so you can review and share those results?

The clean up documentation for the analysis was documented using R markdown file which contains the code and the output of the clean-up. This ensures that anyone can access the data, code used for clean-up and can replicate the processes that were followed to clean the data . This will also ensure credibility of the data by enabling review of work done.

The following is the code used in loading and cleaning the data:

1) Load libraries needed to clean the data.

#Libraries used
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr)
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(plotly)
library(hrbrthemes)
Warning: package ‘hrbrthemes’ was built under R version 4.1.3
Registering Windows fonts with R
NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
      Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
      if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow

2) Prepare the data

Load the data used for analysis. The data is classified as daily and hourly.

#Daily Data
daily_calories<-read.csv("Bellabeat/dailyCalories_merged.csv")
daily_activity<-read.csv("Bellabeat/dailyActivity_merged.csv")
daily_steps<-read.csv("Bellabeat/dailySteps_merged.csv")
daily_intensities<-read.csv("Bellabeat/dailyIntensities_merged.csv")
dailysleep<-read.csv("Bellabeat/sleepDay_merged.csv")
#Hourly data
hourly_calories<-read.csv("Bellabeat/hourlyCalories_merged.csv")
hourly_steps<-read.csv("Bellabeat/hourlySteps_merged.csv")
hourly_intensities<-read.csv("Bellabeat/hourlyIntensities_merged.csv")

2) Clean the data

#Daily Activity Data
#1)Remove rows with nulls
daily_activity<-na.omit(daily_activity)
#2)Change date format
daily_activity$ActivityDate=as.POSIXct(daily_activity$ActivityDate, format="%m/%d/%Y", tz=Sys.timezone())
#3)Remove duplicates
daily_activity%>%distinct(daily_activity$Id, .keep_all = TRUE)
print(head(daily_activity))

Get a summary of the data

#Get a summary of the data
summary(daily_activity)
       Id            ActivityDate         TotalSteps    TotalDistance    TrackerDistance 
 Min.   :1.504e+09   Length:940         Min.   :    0   Min.   : 0.000   Min.   : 0.000  
 1st Qu.:2.320e+09   Class :character   1st Qu.: 3790   1st Qu.: 2.620   1st Qu.: 2.620  
 Median :4.445e+09   Mode  :character   Median : 7406   Median : 5.245   Median : 5.245  
 Mean   :4.855e+09                      Mean   : 7638   Mean   : 5.490   Mean   : 5.475  
 3rd Qu.:6.962e+09                      3rd Qu.:10727   3rd Qu.: 7.713   3rd Qu.: 7.710  
 Max.   :8.878e+09                      Max.   :36019   Max.   :28.030   Max.   :28.030  
 LoggedActivitiesDistance VeryActiveDistance ModeratelyActiveDistance LightActiveDistance
 Min.   :0.0000           Min.   : 0.000     Min.   :0.0000           Min.   : 0.000     
 1st Qu.:0.0000           1st Qu.: 0.000     1st Qu.:0.0000           1st Qu.: 1.945     
 Median :0.0000           Median : 0.210     Median :0.2400           Median : 3.365     
 Mean   :0.1082           Mean   : 1.503     Mean   :0.5675           Mean   : 3.341     
 3rd Qu.:0.0000           3rd Qu.: 2.053     3rd Qu.:0.8000           3rd Qu.: 4.782     
 Max.   :4.9421           Max.   :21.920     Max.   :6.4800           Max.   :10.710     
 SedentaryActiveDistance VeryActiveMinutes FairlyActiveMinutes LightlyActiveMinutes
 Min.   :0.000000        Min.   :  0.00    Min.   :  0.00      Min.   :  0.0       
 1st Qu.:0.000000        1st Qu.:  0.00    1st Qu.:  0.00      1st Qu.:127.0       
 Median :0.000000        Median :  4.00    Median :  6.00      Median :199.0       
 Mean   :0.001606        Mean   : 21.16    Mean   : 13.56      Mean   :192.8       
 3rd Qu.:0.000000        3rd Qu.: 32.00    3rd Qu.: 19.00      3rd Qu.:264.0       
 Max.   :0.110000        Max.   :210.00    Max.   :143.00      Max.   :518.0       
 SedentaryMinutes    Calories   
 Min.   :   0.0   Min.   :   0  
 1st Qu.: 729.8   1st Qu.:1828  
 Median :1057.5   Median :2134  
 Mean   : 991.2   Mean   :2304  
 3rd Qu.:1229.5   3rd Qu.:2793  
 Max.   :1440.0   Max.   :4900  
#Daily Sleep
#Get the description of the dataframe.
str(dailysleep)
'data.frame':   413 obs. of  5 variables:
 $ Id                : num  1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
 $ SleepDay          : POSIXct, format: "2016-04-12" "2016-04-13" "2016-04-15" ...
 $ TotalSleepRecords : int  1 2 1 2 1 1 1 1 1 1 ...
 $ TotalMinutesAsleep: int  327 384 412 340 700 304 360 325 361 430 ...
 $ TotalTimeInBed    : int  346 407 442 367 712 320 377 364 384 449 ...
#1)Remove rows with nulls
dailysleep<-na.omit(dailysleep)
#2)Remove duplicates
dailysleep%>%distinct(dailysleep$Id, .keep_all = TRUE)
#3)Clean date format
dailysleep[['SleepDay']] <- as.POSIXct(dailysleep$SleepDay, format="%m/%d/%Y", tz=Sys.timezone())
#Rename
names(dailysleep)[names(dailysleep) == 'SleepDay'] <- "ActivityDate"
print(head(dailysleep))
#Hourly calories
str(hourly_calories)
'data.frame':   22099 obs. of  4 variables:
 $ Id          : num  1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
 $ ActivityHour: POSIXct, format: "2016-04-12 00:00:00" "2016-04-12 01:00:00" "2016-04-12 02:00:00" ...
 $ Calories    : int  81 61 59 47 48 48 48 47 68 141 ...
 $ Time        : chr  "00:00:00" "01:00:00" "02:00:00" "03:00:00" ...
hourly_calories$ActivityHour=as.POSIXct(hourly_calories$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_calories$Time<-format(hourly_calories$ActivityHour, format = "%H:%M:%S")
print(head(hourly_calories))
#Hourly Steps
str(hourly_steps)
'data.frame':   22099 obs. of  4 variables:
 $ Id          : num  1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
 $ ActivityHour: POSIXct, format: "2016-04-12 00:00:00" "2016-04-12 01:00:00" "2016-04-12 02:00:00" ...
 $ StepTotal   : int  373 160 151 0 0 0 0 0 250 1864 ...
 $ Time        : chr  "00:00:00" "01:00:00" "02:00:00" "03:00:00" ...
hourly_steps$ActivityHour=as.POSIXct(hourly_steps$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_steps$Time<-format(hourly_steps$ActivityHour, format = "%H:%M:%S")
print(head(hourly_steps))
#Merge sleep dataset with the sleep dataset
Daily_data<-inner_join(daily_activity, dailysleep, by=c("Id","ActivityDate"))
Daily_data$month <-months(Daily_data$ActivityDate)
Daily_data$weekday <-weekdays(Daily_data$ActivityDate)
print(head(Daily_data))
NA

Step 4 : Analyse and Share

In order to visualize the data, I had to analyse the datasets based on the analysis. I subset the datasets to gain more insights from the data and identify trends that can be used to solve the business task.

Insight 1: How many calories are users burning per hour?

This will help us get insights on when the users are most active during the day.

#Bar chart of calories burnt per hour
#Libraries
library(ggplot2)
library(hrbrthemes)
#Preparation of dataframe
hourly_cal_new <- hourly_calories %>%
  group_by(Time) %>%
  drop_na() %>%
  summarise(total_hourly_calories = sum(Calories))

#BarPlot
ggplot(data=hourly_cal_new, aes(x=Time, y=total_hourly_calories)) + geom_histogram(stat = "identity", fill='darkblue') +
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title="Total Calories vs. Time")
Warning: Ignoring unknown parameters: binwidth, bins, pad

From the visualization, we can note that users are active from 5 am to 11pm. The peak of activity is from 4 pm to 7 pm.

Insight 2: How many step are taken per hour?

This will help us get insights on when the users are most active during the day and when they are out and about getting exercise.

#Line plot of avg steps per hour
# Libraries
library(ggplot2)
library(dplyr)
library(hrbrthemes)

hourly_steps_new <- hourly_steps %>%
  group_by(Time) %>%
  drop_na() %>%
  summarise(total_hourly_steps = mean(StepTotal))
#print(hourly_steps_new)

# Plot
hourly_steps_new %>%
  ggplot( aes(x=Time, y=total_hourly_steps)) +
  geom_line( color="grey") +
  geom_point(shape=21, color="black", fill="#69b3a2", size=2) +
  theme_ipsum() +
  ggtitle("Average Steps per hour")
geom_path: Each group consists of only one observation. Do you need to adjust the group
aesthetic?
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database

From the visualization, we note that users take are active in recording their steps from 6am to 7 pm. The peak of activity from is between 3pm to 6pm.

Insight 3: How long are people winding down in order to get sleep

This will help analyse the sleep patterns of the users.

#Lollipop graph - total time in bed vs time asleep
weekday_sleep <- Daily_data %>%
  group_by(weekday) %>%
  drop_na() %>%
  summarise(total_min_asleep = sum(TotalMinutesAsleep),
            total_min_in_bed = sum(TotalTimeInBed))
print(weekday_sleep)

# Plot
ggplot(weekday_sleep) +
  geom_segment( aes(x=weekday, xend=weekday, y=total_min_asleep, yend=total_min_in_bed), color="grey") +
  geom_point( aes(x=weekday, y=total_min_asleep), color=rgb(0.2,0.7,0.1,0.5), size=3 ) +
  geom_point( aes(x=weekday, y=total_min_in_bed), color=rgb(0.7,0.2,0.1,0.5), size=3 ) +
  coord_flip()+
  theme_ipsum() +
  theme(
    legend.position = "left",
  ) +
  xlab("Weekday") +
  ylab("Total Minutes")+
  ggtitle("Time in Bed vs Time Asleep per weekday")
Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)) :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database
Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database

From the lollipop graph, we can identify that most users sleep less on Mondays and they take longer to fall asleep on Sunday. This is a classic case of Sunday insomnia.

Insight 4: How can we classify users of fitbit applications

This will the percentage of users are reliant on fitbit apps and devices to track their activity during the day.

#users
daily_average <- Daily_data %>%
  group_by(Id) %>%
  summarise (mean_daily_steps = mean(TotalSteps),
             mean_daily_calories = mean(Calories),
             mean_distance = mean(TotalDistance),
             mean_daily_sleep = mean(TotalMinutesAsleep))

head(daily_average)
user_type <- daily_average %>%
  mutate(user_type = case_when(
    mean_daily_steps < 5000 ~ "Sedentary",
    mean_daily_steps >= 5000 & mean_daily_steps < 7499 ~ "Lightly active", 
    mean_daily_steps >= 7500 & mean_daily_steps < 9999 ~ "Moderately active", 
    mean_daily_steps >= 10000 ~ "Very active"
  ))

head(user_type)
#pie chart
library(plotly)
user_types<-c("Sedentary users", "Lightly active users", "Moderately active users", "Very active users")
sedentary<-nrow(user_type[user_type$user_type == "Sedentary",])
light<-nrow(user_type[user_type$user_type == "Lightly active",])
moderate<-nrow(user_type[user_type$user_type == "Moderately active",])
active<-nrow(user_type[user_type$user_type == "Very active",])
count_users<-c(sedentary, light, moderate, active)
user_types_df<-data.frame(user_types,count_users)

fig <- plot_ly(user_types_df, labels = ~user_types, values = ~count_users, type = 'pie')
fig <- fig %>% layout(title = 'Classification of Users based on daily total distance',
                      xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
                      yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

fig

From the visualization, we identify that majority of the users are moderately active. This means that users are moderately using fitbit applications to monitor their activity during the day.

Insight 5: Are there correlations between total calories burnt and total steps taken?

This will help identify if the users are tracking the steps which will correlate to the calories burnt data produced by fitbit devices.

#Correlation between total daily calories and steps
ggplot(Daily_data, aes(x=Calories, y=TotalSteps))+
  geom_jitter() +
  geom_smooth(color = "blue") + 
  labs(title = "Daily calories burnt vs Total Steps", x = "Calories burnt", y= "Daily Steps") +
  theme(panel.background = element_blank(),
        plot.title = element_text( size=14))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

From the visualization, we can see that there is a positive correlation between the calories burnt and the steps taken by a user. The more the steps taken, the more calories a user burns.

Insight 6: Is there a correlation between the total steps and minutes of sleep?

This will help identify if sleeping habits affect the activity of a user during the day.

#Correlation between Steps and Total Minutes Asleep
ggplot(Daily_data, aes(x=TotalSteps, y=TotalMinutesAsleep))+
  geom_jitter() +
  geom_smooth(color = "green") + 
  labs(title = "Daily steps vs Minutes asleep", x = "Daily steps", y= "Minutes asleep") +
  theme(panel.background = element_blank(),
        plot.title = element_text( size=14))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

From the visualization, we can note that there is no correlation between the minutes of sleep and daily steps. We cannot establish if the more steps one take will assure a good sleep session for a user.

Step 5: Act

From the insights derived from the sample fitbit datasets, I would recommend the following to the stakeholders in order to boost the use of BellaBeat app and how this can boost marketing of the use of Leaf, Time and Spring.

1) Increase the intensity of online marketting from 6 am - 10 am , 2pm - 3pm, and 8pm - 23pm Scheduling adverts on media channels during the hours will help users think of using BellaBeat products when they are more active.

2) Introduce step notifications in the BellaBeat App to notify users at 12pm, 3pm and 9pm of their step count. This will help users monitor their step count and plan their daily activities

3) Introduce sleep notification to help users not use their phones when they are in bed. This will help them get adequate sleep during the night.

4) Increase marketting campaigns to target light and sedentary users by advertising how BellaBeat can help them meet their fitness goals based on activity logged and how it corresponds to calories burnt.

5) Introduce a reward system for users to encourage users to log their activity in BellaBeat App. We can also help introduce them to other BellaBeat products that will automatically log the information for them without the need of manually entering the information.

LS0tDQp0aXRsZTogIkJlbGxhYmVhdCBDYXNlIFN0dWR5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyAqKkdvb2dsZSBEYXRhIEFuYWx5dGljcyBQcm9mZXNzaW9uYWwgQ2Fwc3RvbmUgUHJvamVjdCAtIEJlbGxhQmVhdCoqDQoNCkJlbGxhYmVhdCwgYSBoaWdoLXRlY2ggbWFudWZhY3R1cmVyIG9mIGhlYWx0aC1mb2N1c2VkIHByb2R1Y3RzIGZvciB3b21lbi4gSW4gb3JkZXIgdG8gYW5zd2VyIHRoZSBrZXkgYnVzaW5lc3MgcXVlc3Rpb25zLCBJIGZvbGxvd2VkIHRoZSBzdGVwcyBvZiB0aGUgZGF0YSBhbmFseXNpcyBwcm9jZXNzOiAqKmFzayoqLCAqKnByZXBhcmUqKiwgKipwcm9jZXNzKiosICoqYW5hbHl6ZSoqLCAqKnNoYXJlKiosIGFuZCAqKmFjdCoqLg0KDQpJIGFjdGVkIGFzIGEganVuaW9yIGRhdGEgYW5hbHlzdCB3b3JraW5nIG9uIHRoZSBtYXJrZXRpbmcgYW5hbHlzdCB0ZWFtIGF0IEJlbGxhYmVhdC4gVGhlDQpDaGllZiBDcmVhdGl2ZSBPZmZpY2VyIG9mIEJlbGxhYmVhdCwgYmVsaWV2ZXMgdGhhdCBhbmFseXppbmcgc21hcnQgZGV2aWNlIGZpdG5lc3MgZGF0YSBjb3VsZCBoZWxwIHVubG9jayBuZXcgZ3Jvd3RoIG9wcG9ydHVuaXRpZXMgZm9yIHRoZSBjb21wYW55LiBBcyBwYXJ0IG9mIHRoZSBkYXRhIGFuYWx5dGljcyB0ZWFtLCBJIGhhdmUgYmVlbiBhc2tlZCB0byBmb2N1cyBvbiBvbmUgb2YgQmVsbGFiZWF0J3MgcHJvZHVjdHMgYW5kIGFuYWx5emUgc21hcnQgZGV2aWNlIGRhdGEgdG8gZ2FpbiBpbnNpZ2h0IGludG8gaG93IGNvbnN1bWVycyBhcmUgdXNpbmcgdGhlaXIgc21hcnQgZGV2aWNlcy4gVGhlIGluc2lnaHRzIEkgZGlzY292ZXIgd2lsbCB0aGVuIGhlbHAgZ3VpZGUgbWFya2V0aW5nIHN0cmF0ZWd5IGZvciB0aGUgY29tcGFueS4gSSB3aWxsIHByZXNlbnQgeW91ciBhbmFseXNpcyB0byB0aGUgQmVsbGFiZWF0IGV4ZWN1dGl2ZSB0ZWFtIGFsb25nIHdpdGggeW91ciBoaWdoLWxldmVsIHJlY29tbWVuZGF0aW9ucyBmb3IgQmVsbGFiZWF0J3MgbWFya2V0aW5nIHN0cmF0ZWd5LiBBbmFseXNpcyBvZiBCZWxsYWJlYXQncyBhdmFpbGFibGUgY29uc3VtZXIgZGF0YSB3b3VsZCByZXZlYWwgbW9yZSBvcHBvcnR1bml0aWVzIGZvciBncm93dGguIFRoZSBhbmFseXNpcyBpcyB0byBmb2N1cyBvbiBhDQpCZWxsYWJlYXQgcHJvZHVjdCBhbmQgYW5hbHl6ZSBzbWFydCBkZXZpY2UgdXNhZ2UgZGF0YSBpbiBvcmRlciB0byBnYWluIGluc2lnaHQgaW50byBob3cgcGVvcGxlIGFyZSBhbHJlYWR5IHVzaW5nIHRoZWlyIHNtYXJ0IGRldmljZXMuIFRoZW4sIHVzaW5nIHRoaXMgaW5mb3JtYXRpb24sIG1ha2UgaGlnaC1sZXZlbCByZWNvbW1lbmRhdGlvbnMgZm9yIGhvdyB0aGVzZSB0cmVuZHMgY2FuIGluZm9ybSBCZWxsYWJlYXQgbWFya2V0aW5nIHN0cmF0ZWd5Lg0KDQojIyAqKlN0ZXAgMTogQXNrKioNCg0KSW4gbXkgaHlwb3RoZXRpY2FsIHJvbGUgYXMgdGhlIEp1bmlvciBkYXRhIGFuYWx5c3QgZm9yIEJlbGxhYmVhdCdzIG1hcmtldGluZyB0ZWFtLCB0aGUgQ0NPIGFza3MgbWUgdG8gYW5hbHl6ZSBzbWFydCBkZXZpY2UgdXNhZ2UgZGF0YSBpbiBvcmRlciB0byBnYWluIGluc2lnaHQgaW50byBob3cgY29uc3VtZXJzIHVzZSBub24tQmVsbGFiZWF0IHNtYXJ0IGRldmljZXMuIFNoZSB0aGVuIHdhbnRzIG1lIHRvIHNlbGVjdCBvbmUgQmVsbGFiZWF0IHByb2R1Y3QgdG8gYXBwbHkgdGhlc2UgaW5zaWdodHMgdG8gaW4geW91ciBwcmVzZW50YXRpb24uIFRoZXNlIHF1ZXN0aW9ucyBndWlkZWQgbXkgYW5hbHlzaXM6DQoNCjEuICBXaGF0IGFyZSBzb21lIHRyZW5kcyBpbiBzbWFydCBkZXZpY2UgdXNhZ2U/DQoNCmBgYHs9aHRtbH0NCjwhLS0gLS0+DQpgYGANCjIuICBIb3cgY291bGQgdGhlc2UgdHJlbmRzIGFwcGx5IHRvIEJlbGxhYmVhdCBjdXN0b21lcnM/DQoNCmBgYHs9aHRtbH0NCjwhLS0gLS0+DQpgYGANCjMuICBIb3cgY291bGQgdGhlc2UgdHJlbmRzIGhlbHAgaW5mbHVlbmNlIEJlbGxhYmVhdCBtYXJrZXRpbmcgc3RyYXRlZ3k/DQoNCkFzIHBhcnQgb2YgdGhlIGFzayBwcm9jZXNzIG9mIGRhdGEgYW5hbHlzaXMsIEkgaWRlbnRpZmllZCB0aGUga2V5IHRhc2sgb2YgdGhlIGFuYWx5c2lzIGFuZCB0aGUgc3Rha2Vob2xkZXJzIHdobyBJIHdvdWxkIG1ha2UgcmVjb21tZW5kYXRpb25zIGJhc2VkIG9uIHRoZSBpbnNpZ2h0cyBkZXJpdmVkIGZyb20gdGhlIGRhdGEuDQoNCktleSB0YXNrcw0KDQoxXC4gSWRlbnRpZnkgdGhlIGJ1c2luZXNzIHRhc2sgOiBUaGUgbWFpbiBidXNpbmVzcyB0YXNrIGlzIHRvIHVzZQ0KdGhlIHNtYXJ0IGRldmljZXMgZGF0YSB0byBhbmFseXNlIGhvdyB1c2VycyBhcmUgdXNpbmcgc21hcnQgZGV2aWNlcyB0byBtb25pdG9yDQp0aGVpciBhY3Rpdml0eS4NCg0KMlwuIENvbnNpZGVyIGtleSBzdGFrZWhvbGRlcnMgOiB0aGUgbWFpbiBzdGFrZWhvbGRlcnMgb2YgdGhlDQphbmFseXNpcyBhcmUgdGhlIGV4ZWN1dGl2ZSB0ZWFtIHdoaWNoIGNvbXByaXNlcyBvZiB0aGUgQ0NPICZjby1mb3VuZGVycyx0aGUNCmN1c3RvbWVyIGZhY2luZyB0ZWFtIHdobyBhcmUgdGhlIG1hcmtldGluZyB0ZWFtLCBhbmQgdGhlIGFuYWx5dGljcyB0ZWFtIHdobyBhcmUNCmNhcnJ5aW5nIG91dCB0aGUgYW5hbHlzaXMuDQoNCioqRGVsaXZlcmFibGU6IMKgQSBjbGVhciBzdGF0ZW1lbnQgb2YgdGhlIGJ1c2luZXNzIHRhc2sqKg0KDQpUaGUgbWFpbiBkZWxpdmVyYWJsZSBvZiB0aGUgQXNrIFBoYXNlIGlzIGEgY2xlYXIgYnVzaW5lc3MgdGFzayB3aGljaCBJIGRvY3VtZW50ZWQgYXMgYmVsb3c6DQoNCkJlbGxhYmVhdCB3b3VsZCBsaWtlIHRvIGlkZW50aWZ5IHRoZSB1c2FnZSBvZiBsaWZlc3R5bGUgbGlmZXN0eWxlIHNtYXJ0IGRldmljZXMgYnkgdXNlcnMuIEluIG9yZGVyIHRvIGRvIHNvLCB3ZSB3aWxsIGFuYWx5c2UgdGhlIGRhdGEgY29sbGVjdGVkIGZyb20gc21hcnQgZGV2aWNlcyB1c2VycyB3aG8gZG8gbm90IHVzZSBCZWxsYUJlYXQgdG8gaWRlbnRpZnkgdHJlbmRzIG9mIGhvdyB0aGV5IHVzZSBzbWFydCBkZXZpY2VzLiBUaGlzIHdpbGwgaGVscCBpbmZsdWVuY2UgdGhlIG1hcmtldGluZyBzdHJhdGVneSBvZiBCZWxsYUJlYXQgdG8NCmFkdmVydGlzZSB0aGVpciBwcm9kdWN0cyB0byBtb3JlIHVzZXJzLg0KDQojIyAqKlN0ZXAgMjogUHJlcGFyZSoqDQoNClRoZSBDQ08gZW5jb3VyYWdlcyB0aGUgdXNlIHB1YmxpYyBkYXRhIHRoYXQgZXhwbG9yZXMgc21hcnQgZGV2aWNlIHVzZXJzJyBkYWlseSBoYWJpdHMuIFNoZSBwb2ludHMgdXMgdG8gYSBzcGVjaWZpYyBkYXRhIHNldDoNCg0K4pePIFsqKkZpdEJpdCBGaXRuZXNzIFRyYWNrZXIgRGF0YSoqXXsudWx9IChDQzA6UHVibGljIERvbWFpbiwgZGF0YXNldCBtYWRlIGF2YWlsYWJsZSB0aHJvdWdoIFtNb2JpdXNdey51bH0pOiBUaGlzIEthZ2dsZSBkYXRhIHNldCBjb250YWlucyBwZXJzb25hbCBmaXRuZXNzIHRyYWNrZXIgZnJvbSB0aGlydHkgZml0Yml0IHVzZXJzLiBUaGlydHkgZWxpZ2libGUgRml0Yml0IHVzZXJzIGNvbnNlbnRlZCB0byB0aGUgc3VibWlzc2lvbiBvZiBwZXJzb25hbCB0cmFja2VyIGRhdGEsIGluY2x1ZGluZyBtaW51dGUtbGV2ZWwgb3V0cHV0IGZvciBwaHlzaWNhbCBhY3Rpdml0eSwgaGVhcnQgcmF0ZSwgYW5kIHNsZWVwIG1vbml0b3JpbmcuIEl0IGluY2x1ZGVzIGluZm9ybWF0aW9uIGFib3V0IGRhaWx5IGFjdGl2aXR5LCBzdGVwcywgYW5kIGhlYXJ0IHJhdGUgdGhhdCBjYW4gYmUgdXNlZCB0byBleHBsb3JlIHVzZXJzJyBoYWJpdHMuDQoNClRoZSBDQ08gdGVsbHMgdXMgdGhhdCB0aGlzIGRhdGEgc2V0IG1pZ2h0IGhhdmUgc29tZSBsaW1pdGF0aW9ucywgYW5kIGVuY291cmFnZXMgdXMgdG8gY29uc2lkZXIgYWRkaW5nIGFub3RoZXIgZGF0YSB0byBoZWxwIGFkZHJlc3MgdGhvc2UgbGltaXRhdGlvbnMgYXMgeW91IGJlZ2luIHRvIHdvcmsgbW9yZSB3aXRoIHRoaXMgZGF0YS4NCg0KVGhlIGd1aWRpbmcgcXVlc3Rpb25zIGluIHRoZSBwcmVwYXJhdGlvbiBvZiB0aGUgZGF0YSBhcmUgYXMgYmVsb3c6DQoNCuKXjyAqKldoZXJlIGlzIHlvdXIgZGF0YSBzdG9yZWQ/KioNCg0KVGhlIGRhdGEgaXMgc3RvcmVkIG9uIEthZ2dsZSBhcyBwYXJ0IG9mIHRoZSBGaXRCaXQgRml0bmVzcyBUcmFja2VyIGRhdGFzZXQgbWFkZSBhdmFpbGFibGUgdGhyb3VnaCBNb2JpdXMuIFRoZSBkYXRhIHNldCBjb250YWlucyBwZXJzb25hbCBmaXRuZXNzIHRyYWNrZXIgZnJvbSB0aGlydHkgZml0Yml0IHVzZXJzIHdobyBjb25zZW50ZWQgdGhlDQpjb2xsZWN0aW9uIG9mIHRoZWlyIHBlcnNvbmFsIHRyYWNrZXIgZGF0YSBpbmNsdWRpbmcgbWludXRlLWxldmVsIG91dHB1dCBmb3IgcGh5c2ljYWwgYWN0aXZpdHksIGhlYXJ0IHJhdGUsIGFuZCBzbGVlcCBtb25pdG9yaW5nLiBJdCBpbmNsdWRlcyBpbmZvcm1hdGlvbiBhYm91dCBkYWlseSBhY3Rpdml0eSwgc3RlcHMsIGFuZCBoZWFydCByYXRlIHRoYXQgY2FuIGJlIHVzZWQgdG8gZXhwbG9yZSB1c2VycydoYWJpdHMuDQoNCuKXjyAqKkhvdyBpcyB0aGUgZGF0YSBvcmdhbml6ZWQ/IElzIGl0IGluIGxvbmcgb3Igd2lkZSBmb3JtYXQ/KioNCg0KVGhlIGRhdGEgaXMgc3RvcmVkIGluIGNzdiBmaWxlcyB3aGljaCBhcmUgb3JnYW5pc2VkIGluIHRlcm1zIG9mIG1pbnV0ZSwgaG91cmx5IGFuZCBkYWlseSBtZWFzdXJlbWVudHMgb2YgY2Fsb3JpZXMgaW50YWtlLCBzdGVwcywgc2xlZXAgYW5kIGFjdGl2aXR5IGludGVuc2l0eS4NCg0K4pePICoqQXJlIHRoZXJlIGlzc3VlcyB3aXRoIGJpYXMgb3IgY3JlZGliaWxpdHkgaW4gdGhpcyBkYXRhPyBEb2VzIHlvdXIgZGF0YSBST0NDQz8qKg0KDQpUbyBhY2Nlc3MgdGhlIGNyZWRpYmlsaXR5IG9mIHRoZSBkYXRhLCBJIGZvbGxvd2VkIHRoZSBST0NDQyBjcml0ZXJpYSBieSBHb29nbGUuIEZvciBlYWNoIG9mIHRoZSBkYXRhc2V0cyBJIGRldGVybWluZWQgaWYgdGhlIGRhdGEgaXM6DQoNCjEuICBSZWxpYWJsZTogVGhlIGRhdGFzZXQgaXMgcmVsaWFibGUgZm9yIHRoZSBhbmFseXNpcyBhcyBpdCBjb250YWlucyBmaXRuZXNzIGRhdGEgcmVsYXRpbmcgdG8gc2xlZXAsIHN0ZXBzIHRha2VuLCBjYWxvcnkgaW50YWtlIGFuZCBoZWFydCByYXRlLiBUaGUgZGF0YSBoZWxwcyB1cyB0byBnZXQgaW5zaWdodHMgaW50byB0aGUgdXNlIG9mIGZpdGJpdHMgYnkgdXNlcnMuDQoyLiAgT3JpZ2luYWw6IERhdGEgd2FzIGNvbGxlY3RlZCBieSBmaXRuZXNzIHRyYWNrZXIgdXNlcnMuDQozLiAgQ29tcHJlaGVuc2l2ZTogRGF0YSB3YXMgb3JnYW5pc2VkIGluIGFjY29yZGluZyB0byBtaW51dGUsIGhvdXIgYW5kIGRhaWx5IG1lYXN1cmVtZW50cyBoZW5jZSBpdCB3YXMgZWFzeSB0byB1bmRlcnN0YW5kLg0KNC4gIEN1cnJlbnQ6IERhdGFzZXQgY29tcHJpc2VkIG9mIHVzZXIgYWN0aXZpdHkgZm9yIHRoZSAxMiBtb250aHMgaW4gMjAxNiB3aGljaCBpcyBjdXJyZW50Lg0KNS4gIENpdGVkOiBUaGUgZGF0YSBpcyBub3QgY2l0ZWQsIGl0IGlzIGhvd2V2ZXIgYXZhaWxhYmxlIG9uIEthZ2dsZS4NCg0K4pePICoqSG93IGFyZSB5b3UgYWRkcmVzc2luZyBsaWNlbnNpbmcsIHByaXZhY3ksIHNlY3VyaXR5LCBhbmQgYWNjZXNzaWJpbGl0eT8qKg0KDQpUaGUgZGF0YSB3YXMgYW5vbnltaXNlZCB3aXRoIG5vIFBJSSBpbmNsdWRlZCBpbiB0aGUgZGF0YS4gVGhlIGRhdGEgd2FzIGNsYXNzaWZpZWQgdXNpbmcgYSB1bmlxdWUgSUQgdGhhdCB3YXMgdXNlZCB0byBsaW5rIHRoZSBkaWZmZXJlbnQgZGF0YXNldHMuDQoNCuKXjyAqKkhvdyBkaWQgeW91IHZlcmlmeSB0aGUgZGF0YSdzIGludGVncml0eT8qKg0KDQpUaGUgZGF0YSBjYW4gYmUgc2FpZCB0byBoYXZlIGludGVncml0eSBhcyBpdCBpcyBwdWJsaWNseSBhdmFpbGFibGUgb24gS2FnZ2xlIHdoaWNoIGlzIGEgcHVibGljIHBsYXRmb3JtIGZvciBkYXRhLiBUbyBjaGVjayB0aGUgZGF0YXNldCBpbnRlZ3JpdHksIEkgY29uZmlybWVkIHRoZSBlbnRpdHkgYW5kIHJlZmVyZW50aWFsIGludGVncml0eSBvZiB0aGUgZGF0YS4gVGhlIGRhdGEgaGFkIHVuaXF1ZSBJZHMgdGhhdCBjb3JyZWxhdGVkIHRvIHRoZSB1c2VycyB3aG8gc3VibWl0dGVkIHRoZSBkYXRhLiBUaGUgdW5pcXVlIElkIHdhcyBjb25zaXN0ZW50IHRocm91Z2hvdXQgYWxsIHRoZSBkYXRhc2V0cy4NCg0K4pePICoqSG93IGRvZXMgaXQgaGVscCB5b3UgYW5zd2VyIHlvdXIgcXVlc3Rpb24/KioNCg0KVGhlIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gY29sbGVjdGVkIGJ5IDMwIGZpdGJpdCB1c2VycyBvdmVyIHR3byBtb250aHMuIFRoaXMgZGF0YSB3aWxsIGhlbHAgbWUgaWRlbnRpZnkgdGhlIHRyZW5kcyBpbiB0aGUgdXNlIG9mIGZpdGJpdCB0cmFja2VycyBoZW5jZSBhbnN3ZXJpbmcgdGhlIHF1ZXN0aW9ucyBpbiB0aGUgYnVzaW5lc3MgdGFzay4NCg0KKiril48gQXJlIHRoZXJlIGFueSBwcm9ibGVtcyB3aXRoIHRoZSBkYXRhPyoqDQoNClRoZSBkYXRhIGhhcyBkYXRlIGNvbHVtbnMgdGhhdCBpcyBzdG9yZWQgYXMgYSBzdHJpbmcuIEluIG9yZGVyIHRvIHByb3Blcmx5IGFuYWx5c2UgdGhlIGRhdGEsIEkgY2hhbmdlZCBhbGwgZGF0ZSBjb2x1bW5zIGludG8gdGhlIGRhdGV0aW1lIGZvcm1hdCBpbiBSIHVzaW5nIHRoZSBQT1NJWCBmdW5jdGlvbi4NCg0KIyMgU3RlcCAzOiBQcm9jZXNzDQoNClRoZSBwcm9jZXNzIHBoYXNlIGlzIHRvIGVuc3VyZSB0aGUgZGF0YSBpcyBjb21wbGV0ZSBhbmQgY2FuIGJlIHVzZWQgaW4gdGhlIGFuYWx5emUgcGhhc2UuIEluIG9yZGVyIHRvIHByb2Nlc3MgdGhlIGRhdGEsIEkgdXNlZCB0aGUgZm9sbG93aW5nIGd1aWRpbmcgcXVlc3Rpb25zOg0KDQpHdWlkaW5nIHF1ZXN0aW9ucw0KDQril48gKipXaGF0IHRvb2xzIGFyZSB5b3UgY2hvb3NpbmcgYW5kIHdoeT8qKg0KDQpSOiBJIGFtIHVzaW5nIFIgZHVlIHRvIGl0cyBjYXBhYmlsaXRpZXMgaW4gZGF0YSBjbGVhbmluZywgam9pbmluZyB0aGUgZGF0YXNldHMgYW5kIHZpc3VhbGl6ZSB0aGUgZGF0YSB0byBnZXQga2V5IGluc2lnaHRzIHRvIHNvbHZlIHRoZSBidXNpbmVzcyB0YXNrLg0KDQril48gKipIYXZlIHlvdSBlbnN1cmVkIHlvdXIgZGF0YSdzIGludGVncml0eT8qKg0KDQpJIGVuc3VyZWQgdGhhdCB0aGUgZGF0YSBoYWQgZW50aXR5IGFuZCByZWZlcmVudGlhbCBpbnRlZ3JpdHkgYnkgY29uZmlybWluZyBhbGwgdXNlciBJZHMgd2VyZSBjb25zaXN0ZW50IGluIGFsbCBkYXRhc2V0cy4NCg0K4pePICoqV2hhdCBzdGVwcyBoYXZlIHlvdSB0YWtlbiB0byBlbnN1cmUgdGhhdCB5b3VyIGRhdGEgaXMgY2xlYW4/KioNCg0KVG8gZW5zdXJlIG15IGRhdGEgaXMgY2xlYW4sIEkgZm9sbG93ZWQgdGhlIGJlbG93IHN0ZXBzOg0KDQoxXCkgUmVtb3ZlZCBkdXBsaWNhdGUgcm93cw0KDQoyXCkgUmVtb3ZlZCByb3dzIHRoYXQgaGF2ZSBudWxsIGNvbHVtbnMNCg0KM1wpIEVuc3VyZWQgdGhlIGRhdGV0aW1lIGNvbHVtbnMgYXJlIHByb3Blcmx5IGZvcm1hdHRlZC4NCg0KKiril48gSG93IGNhbiB5b3UgdmVyaWZ5IHRoYXQgeW91ciBkYXRhIGlzIGNsZWFuIGFuZCByZWFkeSB0byBhbmFseXplPyoqDQpUbyB2ZXJpZnkgdGhhdCB0aGUgZGF0YSB3YXMgY29ycmVjdCB0byB1c2UsIGFuYWx5c2VkIHRoZSBkYXRhc2V0cycgc3VtbWFyeSBzdGF0aXN0aWNzIGluIFIuIFRoaXMgd2lsbCBzaG93IGlmIHRoZXJlIGFyZSBhbnkgbnVsbHMgaW4gdGhlIGRhdGEsIGlkZW50aWZ5IHRoZSBtZWFuLCBtaW4sIG1heCBhbmQgYXZnIG9mIG51bWVyaWNhbCB2YXJpYWJsZXMgdG8gZ2V0IGEgaGlnaGxpZ2h0IG9mIHRoZSBkYXRhLg0KDQoqKuKXjyBIYXZlIHlvdSBkb2N1bWVudGVkIHlvdXIgY2xlYW5pbmcgcHJvY2VzcyBzbyB5b3UgY2FuIHJldmlldyBhbmQgc2hhcmUgdGhvc2UgcmVzdWx0cz8qKg0KDQpUaGUgY2xlYW4gdXAgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGFuYWx5c2lzIHdhcyBkb2N1bWVudGVkIHVzaW5nIFIgbWFya2Rvd24gZmlsZSB3aGljaCBjb250YWlucyB0aGUgY29kZSBhbmQgdGhlIG91dHB1dCBvZiB0aGUgY2xlYW4tdXAuIFRoaXMgZW5zdXJlcyB0aGF0IGFueW9uZSBjYW4gYWNjZXNzIHRoZSBkYXRhLCBjb2RlIHVzZWQgZm9yIGNsZWFuLXVwIGFuZCBjYW4gcmVwbGljYXRlIHRoZSBwcm9jZXNzZXMgdGhhdCB3ZXJlIGZvbGxvd2VkIHRvIGNsZWFuIHRoZSBkYXRhIC4gVGhpcyB3aWxsIGFsc28gZW5zdXJlIGNyZWRpYmlsaXR5IG9mIHRoZSBkYXRhIGJ5IGVuYWJsaW5nIHJldmlldyBvZiB3b3JrIGRvbmUuDQoNClRoZSBmb2xsb3dpbmcgaXMgdGhlIGNvZGUgdXNlZCBpbiBsb2FkaW5nIGFuZCBjbGVhbmluZyB0aGUgZGF0YToNCg0KMVwpIExvYWQgbGlicmFyaWVzIG5lZWRlZCB0byBjbGVhbiB0aGUgZGF0YS4NCg0KYGBge3J9DQojTGlicmFyaWVzIHVzZWQNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KMlwpIFByZXBhcmUgdGhlIGRhdGENCg0KTG9hZCB0aGUgZGF0YSB1c2VkIGZvciBhbmFseXNpcy4gVGhlIGRhdGEgaXMgY2xhc3NpZmllZCBhcyBkYWlseSBhbmQgaG91cmx5Lg0KDQpgYGB7cn0NCiNEYWlseSBEYXRhDQpkYWlseV9jYWxvcmllczwtcmVhZC5jc3YoIkJlbGxhYmVhdC9kYWlseUNhbG9yaWVzX21lcmdlZC5jc3YiKQ0KZGFpbHlfYWN0aXZpdHk8LXJlYWQuY3N2KCJCZWxsYWJlYXQvZGFpbHlBY3Rpdml0eV9tZXJnZWQuY3N2IikNCmRhaWx5X3N0ZXBzPC1yZWFkLmNzdigiQmVsbGFiZWF0L2RhaWx5U3RlcHNfbWVyZ2VkLmNzdiIpDQpkYWlseV9pbnRlbnNpdGllczwtcmVhZC5jc3YoIkJlbGxhYmVhdC9kYWlseUludGVuc2l0aWVzX21lcmdlZC5jc3YiKQ0KZGFpbHlzbGVlcDwtcmVhZC5jc3YoIkJlbGxhYmVhdC9zbGVlcERheV9tZXJnZWQuY3N2IikNCmBgYA0KDQpgYGB7cn0NCiNIb3VybHkgZGF0YQ0KaG91cmx5X2NhbG9yaWVzPC1yZWFkLmNzdigiQmVsbGFiZWF0L2hvdXJseUNhbG9yaWVzX21lcmdlZC5jc3YiKQ0KaG91cmx5X3N0ZXBzPC1yZWFkLmNzdigiQmVsbGFiZWF0L2hvdXJseVN0ZXBzX21lcmdlZC5jc3YiKQ0KaG91cmx5X2ludGVuc2l0aWVzPC1yZWFkLmNzdigiQmVsbGFiZWF0L2hvdXJseUludGVuc2l0aWVzX21lcmdlZC5jc3YiKQ0KYGBgDQoNCjJcKSBDbGVhbiB0aGUgZGF0YQ0KDQpgYGB7cn0NCiNEYWlseSBBY3Rpdml0eSBEYXRhDQojMSlSZW1vdmUgcm93cyB3aXRoIG51bGxzDQpkYWlseV9hY3Rpdml0eTwtbmEub21pdChkYWlseV9hY3Rpdml0eSkNCiMyKUNoYW5nZSBkYXRlIGZvcm1hdA0KZGFpbHlfYWN0aXZpdHkkQWN0aXZpdHlEYXRlPWFzLlBPU0lYY3QoZGFpbHlfYWN0aXZpdHkkQWN0aXZpdHlEYXRlLCBmb3JtYXQ9IiVtLyVkLyVZIiwgdHo9U3lzLnRpbWV6b25lKCkpDQojMylSZW1vdmUgZHVwbGljYXRlcw0KZGFpbHlfYWN0aXZpdHklPiVkaXN0aW5jdChkYWlseV9hY3Rpdml0eSRJZCwgLmtlZXBfYWxsID0gVFJVRSkNCnByaW50KGhlYWQoZGFpbHlfYWN0aXZpdHkpKQ0KYGBgDQoNCkdldCBhIHN1bW1hcnkgb2YgdGhlIGRhdGENCg0KYGBge3J9DQojR2V0IGEgc3VtbWFyeSBvZiB0aGUgZGF0YQ0Kc3VtbWFyeShkYWlseV9hY3Rpdml0eSkNCg0KYGBgDQoNCmBgYHtyfQ0KI0RhaWx5IFNsZWVwDQojR2V0IHRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YWZyYW1lLg0Kc3RyKGRhaWx5c2xlZXApDQojMSlSZW1vdmUgcm93cyB3aXRoIG51bGxzDQpkYWlseXNsZWVwPC1uYS5vbWl0KGRhaWx5c2xlZXApDQojMilSZW1vdmUgZHVwbGljYXRlcw0KZGFpbHlzbGVlcCU+JWRpc3RpbmN0KGRhaWx5c2xlZXAkSWQsIC5rZWVwX2FsbCA9IFRSVUUpDQojMylDbGVhbiBkYXRlIGZvcm1hdA0KZGFpbHlzbGVlcFtbJ1NsZWVwRGF5J11dIDwtIGFzLlBPU0lYY3QoZGFpbHlzbGVlcCRTbGVlcERheSwgZm9ybWF0PSIlbS8lZC8lWSIsIHR6PVN5cy50aW1lem9uZSgpKQ0KI1JlbmFtZQ0KbmFtZXMoZGFpbHlzbGVlcClbbmFtZXMoZGFpbHlzbGVlcCkgPT0gJ1NsZWVwRGF5J10gPC0gIkFjdGl2aXR5RGF0ZSINCnByaW50KGhlYWQoZGFpbHlzbGVlcCkpDQpgYGANCg0KYGBge3J9DQojSG91cmx5IGNhbG9yaWVzDQpzdHIoaG91cmx5X2NhbG9yaWVzKQ0KaG91cmx5X2NhbG9yaWVzJEFjdGl2aXR5SG91cj1hcy5QT1NJWGN0KGhvdXJseV9jYWxvcmllcyRBY3Rpdml0eUhvdXIsIGZvcm1hdD0iJW0vJWQvJVkgJUk6JU06JVMgJXAiLCB0ej1TeXMudGltZXpvbmUoKSkNCmhvdXJseV9jYWxvcmllcyRUaW1lPC1mb3JtYXQoaG91cmx5X2NhbG9yaWVzJEFjdGl2aXR5SG91ciwgZm9ybWF0ID0gIiVIOiVNOiVTIikNCnByaW50KGhlYWQoaG91cmx5X2NhbG9yaWVzKSkNCmBgYA0KDQpgYGB7cn0NCiNIb3VybHkgU3RlcHMNCnN0cihob3VybHlfc3RlcHMpDQpob3VybHlfc3RlcHMkQWN0aXZpdHlIb3VyPWFzLlBPU0lYY3QoaG91cmx5X3N0ZXBzJEFjdGl2aXR5SG91ciwgZm9ybWF0PSIlbS8lZC8lWSAlSTolTTolUyAlcCIsIHR6PVN5cy50aW1lem9uZSgpKQ0KaG91cmx5X3N0ZXBzJFRpbWU8LWZvcm1hdChob3VybHlfc3RlcHMkQWN0aXZpdHlIb3VyLCBmb3JtYXQgPSAiJUg6JU06JVMiKQ0KcHJpbnQoaGVhZChob3VybHlfc3RlcHMpKQ0KYGBgDQoNCmBgYHtyfQ0KI01lcmdlIHNsZWVwIGRhdGFzZXQgd2l0aCB0aGUgc2xlZXAgZGF0YXNldA0KRGFpbHlfZGF0YTwtaW5uZXJfam9pbihkYWlseV9hY3Rpdml0eSwgZGFpbHlzbGVlcCwgYnk9YygiSWQiLCJBY3Rpdml0eURhdGUiKSkNCkRhaWx5X2RhdGEkbW9udGggPC1tb250aHMoRGFpbHlfZGF0YSRBY3Rpdml0eURhdGUpDQpEYWlseV9kYXRhJHdlZWtkYXkgPC13ZWVrZGF5cyhEYWlseV9kYXRhJEFjdGl2aXR5RGF0ZSkNCnByaW50KGhlYWQoRGFpbHlfZGF0YSkpDQoNCmBgYA0KDQojIyBTdGVwIDQgOiBBbmFseXNlIGFuZCBTaGFyZSANCg0KSW4gb3JkZXIgdG8gdmlzdWFsaXplIHRoZSBkYXRhLCBJIGhhZCB0byBhbmFseXNlIHRoZSBkYXRhc2V0cyBiYXNlZCBvbiB0aGUgYW5hbHlzaXMuIEkgc3Vic2V0IHRoZSBkYXRhc2V0cyB0byBnYWluIG1vcmUgaW5zaWdodHMgZnJvbSB0aGUgZGF0YSBhbmQgaWRlbnRpZnkgdHJlbmRzIHRoYXQgY2FuIGJlIHVzZWQgdG8gc29sdmUgdGhlIGJ1c2luZXNzIHRhc2suDQoNCiMjIyBJbnNpZ2h0IDE6IEhvdyBtYW55IGNhbG9yaWVzIGFyZSB1c2VycyBidXJuaW5nIHBlciBob3VyPw0KDQpUaGlzIHdpbGwgaGVscCB1cyBnZXQgaW5zaWdodHMgb24gd2hlbiB0aGUgdXNlcnMgYXJlIG1vc3QgYWN0aXZlIGR1cmluZyB0aGUgZGF5Lg0KDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShocmJydGhlbWVzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KI0JhciBjaGFydCBvZiBjYWxvcmllcyBidXJudCBwZXIgaG91cg0KI0xpYnJhcmllcw0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShocmJydGhlbWVzKQ0KI1ByZXBhcmF0aW9uIG9mIGRhdGFmcmFtZQ0KaG91cmx5X2NhbF9uZXcgPC0gaG91cmx5X2NhbG9yaWVzICU+JQ0KICBncm91cF9ieShUaW1lKSAlPiUNCiAgZHJvcF9uYSgpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfaG91cmx5X2NhbG9yaWVzID0gc3VtKENhbG9yaWVzKSkNCg0KI0JhclBsb3QNCmdncGxvdChkYXRhPWhvdXJseV9jYWxfbmV3LCBhZXMoeD1UaW1lLCB5PXRvdGFsX2hvdXJseV9jYWxvcmllcykpICsgZ2VvbV9oaXN0b2dyYW0oc3RhdCA9ICJpZGVudGl0eSIsIGZpbGw9J2RhcmtibHVlJykgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICBsYWJzKHRpdGxlPSJUb3RhbCBDYWxvcmllcyB2cy4gVGltZSIpDQpgYGANCg0KRnJvbSB0aGUgdmlzdWFsaXphdGlvbiwgd2UgY2FuIG5vdGUgdGhhdCB1c2VycyBhcmUgYWN0aXZlIGZyb20gNSBhbSB0byAxMXBtLiBUaGUgcGVhayBvZiBhY3Rpdml0eSBpcyBmcm9tIDQgcG0gdG8gNyBwbS4NCg0KIyMjIEluc2lnaHQgMjogIEhvdyBtYW55IHN0ZXAgYXJlIHRha2VuIHBlciBob3VyPw0KDQpUaGlzIHdpbGwgaGVscCB1cyBnZXQgaW5zaWdodHMgb24gd2hlbiB0aGUgdXNlcnMgYXJlIG1vc3QgYWN0aXZlIGR1cmluZyB0aGUgZGF5IGFuZCB3aGVuIHRoZXkgYXJlIG91dCBhbmQgYWJvdXQgZ2V0dGluZyBleGVyY2lzZS4NCg0KYGBge3J9DQojTGluZSBwbG90IG9mIGF2ZyBzdGVwcyBwZXIgaG91cg0KIyBMaWJyYXJpZXMNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGhyYnJ0aGVtZXMpDQoNCmhvdXJseV9zdGVwc19uZXcgPC0gaG91cmx5X3N0ZXBzICU+JQ0KICBncm91cF9ieShUaW1lKSAlPiUNCiAgZHJvcF9uYSgpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfaG91cmx5X3N0ZXBzID0gbWVhbihTdGVwVG90YWwpKQ0KI3ByaW50KGhvdXJseV9zdGVwc19uZXcpDQoNCiMgUGxvdA0KaG91cmx5X3N0ZXBzX25ldyAlPiUNCiAgZ2dwbG90KCBhZXMoeD1UaW1lLCB5PXRvdGFsX2hvdXJseV9zdGVwcykpICsNCiAgZ2VvbV9saW5lKCBjb2xvcj0iZ3JleSIpICsNCiAgZ2VvbV9wb2ludChzaGFwZT0yMSwgY29sb3I9ImJsYWNrIiwgZmlsbD0iIzY5YjNhMiIsIHNpemU9MikgKw0KICB0aGVtZV9pcHN1bSgpICsNCiAgZ2d0aXRsZSgiQXZlcmFnZSBTdGVwcyBwZXIgaG91ciIpDQpgYGANCg0KRnJvbSB0aGUgdmlzdWFsaXphdGlvbiwgd2Ugbm90ZSB0aGF0IHVzZXJzIHRha2UgYXJlIGFjdGl2ZSBpbiByZWNvcmRpbmcgdGhlaXIgc3RlcHMgZnJvbSA2YW0gdG8gNyBwbS4gVGhlIHBlYWsgb2YgYWN0aXZpdHkgZnJvbSBpcyBiZXR3ZWVuIDNwbSB0byA2cG0uDQoNCiMjIyBJbnNpZ2h0IDM6IEhvdyBsb25nIGFyZSBwZW9wbGUgd2luZGluZyBkb3duIGluIG9yZGVyIHRvIGdldCBzbGVlcA0KDQpUaGlzIHdpbGwgaGVscCBhbmFseXNlIHRoZSBzbGVlcCBwYXR0ZXJucyBvZiB0aGUgdXNlcnMuDQoNCmBgYHtyfQ0KI0xvbGxpcG9wIGdyYXBoIC0gdG90YWwgdGltZSBpbiBiZWQgdnMgdGltZSBhc2xlZXANCndlZWtkYXlfc2xlZXAgPC0gRGFpbHlfZGF0YSAlPiUNCiAgZ3JvdXBfYnkod2Vla2RheSkgJT4lDQogIGRyb3BfbmEoKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX21pbl9hc2xlZXAgPSBzdW0oVG90YWxNaW51dGVzQXNsZWVwKSwNCiAgICAgICAgICAgIHRvdGFsX21pbl9pbl9iZWQgPSBzdW0oVG90YWxUaW1lSW5CZWQpKQ0KcHJpbnQod2Vla2RheV9zbGVlcCkNCg0KIyBQbG90DQpnZ3Bsb3Qod2Vla2RheV9zbGVlcCkgKw0KICBnZW9tX3NlZ21lbnQoIGFlcyh4PXdlZWtkYXksIHhlbmQ9d2Vla2RheSwgeT10b3RhbF9taW5fYXNsZWVwLCB5ZW5kPXRvdGFsX21pbl9pbl9iZWQpLCBjb2xvcj0iZ3JleSIpICsNCiAgZ2VvbV9wb2ludCggYWVzKHg9d2Vla2RheSwgeT10b3RhbF9taW5fYXNsZWVwKSwgY29sb3I9cmdiKDAuMiwwLjcsMC4xLDAuNSksIHNpemU9MyApICsNCiAgZ2VvbV9wb2ludCggYWVzKHg9d2Vla2RheSwgeT10b3RhbF9taW5faW5fYmVkKSwgY29sb3I9cmdiKDAuNywwLjIsMC4xLDAuNSksIHNpemU9MyApICsNCiAgY29vcmRfZmxpcCgpKw0KICB0aGVtZV9pcHN1bSgpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiLA0KICApICsNCiAgeGxhYigiV2Vla2RheSIpICsNCiAgeWxhYigiVG90YWwgTWludXRlcyIpKw0KICBnZ3RpdGxlKCJUaW1lIGluIEJlZCB2cyBUaW1lIEFzbGVlcCBwZXIgd2Vla2RheSIpDQpgYGANCg0KRnJvbSB0aGUgbG9sbGlwb3AgZ3JhcGgsIHdlIGNhbiBpZGVudGlmeSB0aGF0IG1vc3QgdXNlcnMgc2xlZXAgbGVzcyBvbiBNb25kYXlzIGFuZCB0aGV5IHRha2UgbG9uZ2VyIHRvIGZhbGwgYXNsZWVwIG9uIFN1bmRheS4gVGhpcyBpcyBhIGNsYXNzaWMgY2FzZSBvZiBTdW5kYXkgaW5zb21uaWEuDQoNCiMjIyBJbnNpZ2h0IDQ6IEhvdyBjYW4gd2UgY2xhc3NpZnkgdXNlcnMgb2YgZml0Yml0IGFwcGxpY2F0aW9ucw0KDQpUaGlzIHdpbGwgdGhlIHBlcmNlbnRhZ2Ugb2YgdXNlcnMgYXJlIHJlbGlhbnQgb24gZml0Yml0IGFwcHMgYW5kIGRldmljZXMgdG8gdHJhY2sgdGhlaXIgYWN0aXZpdHkgZHVyaW5nIHRoZSBkYXkuDQoNCmBgYHtyfQ0KI3VzZXJzDQpkYWlseV9hdmVyYWdlIDwtIERhaWx5X2RhdGEgJT4lDQogIGdyb3VwX2J5KElkKSAlPiUNCiAgc3VtbWFyaXNlIChtZWFuX2RhaWx5X3N0ZXBzID0gbWVhbihUb3RhbFN0ZXBzKSwNCiAgICAgICAgICAgICBtZWFuX2RhaWx5X2NhbG9yaWVzID0gbWVhbihDYWxvcmllcyksDQogICAgICAgICAgICAgbWVhbl9kaXN0YW5jZSA9IG1lYW4oVG90YWxEaXN0YW5jZSksDQogICAgICAgICAgICAgbWVhbl9kYWlseV9zbGVlcCA9IG1lYW4oVG90YWxNaW51dGVzQXNsZWVwKSkNCg0KaGVhZChkYWlseV9hdmVyYWdlKQ0KdXNlcl90eXBlIDwtIGRhaWx5X2F2ZXJhZ2UgJT4lDQogIG11dGF0ZSh1c2VyX3R5cGUgPSBjYXNlX3doZW4oDQogICAgbWVhbl9kYWlseV9zdGVwcyA8IDUwMDAgfiAiU2VkZW50YXJ5IiwNCiAgICBtZWFuX2RhaWx5X3N0ZXBzID49IDUwMDAgJiBtZWFuX2RhaWx5X3N0ZXBzIDwgNzQ5OSB+ICJMaWdodGx5IGFjdGl2ZSIsIA0KICAgIG1lYW5fZGFpbHlfc3RlcHMgPj0gNzUwMCAmIG1lYW5fZGFpbHlfc3RlcHMgPCA5OTk5IH4gIk1vZGVyYXRlbHkgYWN0aXZlIiwgDQogICAgbWVhbl9kYWlseV9zdGVwcyA+PSAxMDAwMCB+ICJWZXJ5IGFjdGl2ZSINCiAgKSkNCg0KaGVhZCh1c2VyX3R5cGUpDQpgYGANCg0KYGBge3J9DQojcGllIGNoYXJ0DQpsaWJyYXJ5KHBsb3RseSkNCnVzZXJfdHlwZXM8LWMoIlNlZGVudGFyeSB1c2VycyIsICJMaWdodGx5IGFjdGl2ZSB1c2VycyIsICJNb2RlcmF0ZWx5IGFjdGl2ZSB1c2VycyIsICJWZXJ5IGFjdGl2ZSB1c2VycyIpDQpzZWRlbnRhcnk8LW5yb3codXNlcl90eXBlW3VzZXJfdHlwZSR1c2VyX3R5cGUgPT0gIlNlZGVudGFyeSIsXSkNCmxpZ2h0PC1ucm93KHVzZXJfdHlwZVt1c2VyX3R5cGUkdXNlcl90eXBlID09ICJMaWdodGx5IGFjdGl2ZSIsXSkNCm1vZGVyYXRlPC1ucm93KHVzZXJfdHlwZVt1c2VyX3R5cGUkdXNlcl90eXBlID09ICJNb2RlcmF0ZWx5IGFjdGl2ZSIsXSkNCmFjdGl2ZTwtbnJvdyh1c2VyX3R5cGVbdXNlcl90eXBlJHVzZXJfdHlwZSA9PSAiVmVyeSBhY3RpdmUiLF0pDQpjb3VudF91c2VyczwtYyhzZWRlbnRhcnksIGxpZ2h0LCBtb2RlcmF0ZSwgYWN0aXZlKQ0KdXNlcl90eXBlc19kZjwtZGF0YS5mcmFtZSh1c2VyX3R5cGVzLGNvdW50X3VzZXJzKQ0KDQpmaWcgPC0gcGxvdF9seSh1c2VyX3R5cGVzX2RmLCBsYWJlbHMgPSB+dXNlcl90eXBlcywgdmFsdWVzID0gfmNvdW50X3VzZXJzLCB0eXBlID0gJ3BpZScpDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQodGl0bGUgPSAnQ2xhc3NpZmljYXRpb24gb2YgVXNlcnMgYmFzZWQgb24gZGFpbHkgdG90YWwgZGlzdGFuY2UnLA0KICAgICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwNCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGQUxTRSwgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSkpDQoNCmZpZw0KYGBgDQoNCkZyb20gdGhlIHZpc3VhbGl6YXRpb24sIHdlIGlkZW50aWZ5IHRoYXQgbWFqb3JpdHkgb2YgdGhlIHVzZXJzIGFyZSBtb2RlcmF0ZWx5IGFjdGl2ZS4gVGhpcyBtZWFucyB0aGF0IHVzZXJzIGFyZSBtb2RlcmF0ZWx5IHVzaW5nIGZpdGJpdCBhcHBsaWNhdGlvbnMgdG8gbW9uaXRvciB0aGVpciBhY3Rpdml0eSBkdXJpbmcgdGhlIGRheS4NCg0KIyMjIEluc2lnaHQgNTogQXJlIHRoZXJlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRvdGFsIGNhbG9yaWVzIGJ1cm50IGFuZCB0b3RhbCBzdGVwcyB0YWtlbj8NCg0KVGhpcyB3aWxsIGhlbHAgaWRlbnRpZnkgaWYgdGhlIHVzZXJzIGFyZSB0cmFja2luZyB0aGUgc3RlcHMgd2hpY2ggd2lsbCBjb3JyZWxhdGUgdG8gdGhlIGNhbG9yaWVzIGJ1cm50IGRhdGEgcHJvZHVjZWQgYnkgZml0Yml0IGRldmljZXMuDQoNCmBgYHtyfQ0KI0NvcnJlbGF0aW9uIGJldHdlZW4gdG90YWwgZGFpbHkgY2Fsb3JpZXMgYW5kIHN0ZXBzDQpnZ3Bsb3QoRGFpbHlfZGF0YSwgYWVzKHg9Q2Fsb3JpZXMsIHk9VG90YWxTdGVwcykpKw0KICBnZW9tX2ppdHRlcigpICsNCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiYmx1ZSIpICsgDQogIGxhYnModGl0bGUgPSAiRGFpbHkgY2Fsb3JpZXMgYnVybnQgdnMgVG90YWwgU3RlcHMiLCB4ID0gIkNhbG9yaWVzIGJ1cm50IiwgeT0gIkRhaWx5IFN0ZXBzIikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCBzaXplPTE0KSkNCmBgYA0KDQpGcm9tIHRoZSB2aXN1YWxpemF0aW9uLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBjYWxvcmllcyBidXJudCBhbmQgdGhlIHN0ZXBzIHRha2VuIGJ5IGEgdXNlci4gVGhlIG1vcmUgdGhlIHN0ZXBzIHRha2VuLCB0aGUgbW9yZSBjYWxvcmllcyBhIHVzZXIgYnVybnMuDQoNCiMjIyBJbnNpZ2h0IDY6IElzIHRoZXJlIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdG90YWwgc3RlcHMgYW5kIG1pbnV0ZXMgb2Ygc2xlZXA/DQoNClRoaXMgd2lsbCBoZWxwIGlkZW50aWZ5IGlmIHNsZWVwaW5nIGhhYml0cyBhZmZlY3QgdGhlIGFjdGl2aXR5IG9mIGEgdXNlciBkdXJpbmcgdGhlIGRheS4NCg0KYGBge3J9DQojQ29ycmVsYXRpb24gYmV0d2VlbiBTdGVwcyBhbmQgVG90YWwgTWludXRlcyBBc2xlZXANCmdncGxvdChEYWlseV9kYXRhLCBhZXMoeD1Ub3RhbFN0ZXBzLCB5PVRvdGFsTWludXRlc0FzbGVlcCkpKw0KICBnZW9tX2ppdHRlcigpICsNCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiZ3JlZW4iKSArIA0KICBsYWJzKHRpdGxlID0gIkRhaWx5IHN0ZXBzIHZzIE1pbnV0ZXMgYXNsZWVwIiwgeCA9ICJEYWlseSBzdGVwcyIsIHk9ICJNaW51dGVzIGFzbGVlcCIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCggc2l6ZT0xNCkpDQpgYGANCg0KRnJvbSB0aGUgdmlzdWFsaXphdGlvbiwgd2UgY2FuIG5vdGUgdGhhdCB0aGVyZSBpcyBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtaW51dGVzIG9mIHNsZWVwIGFuZCBkYWlseSBzdGVwcy4gV2UgY2Fubm90IGVzdGFibGlzaCBpZiB0aGUgbW9yZSBzdGVwcyBvbmUgdGFrZSB3aWxsIGFzc3VyZSBhIGdvb2Qgc2xlZXAgc2Vzc2lvbiBmb3IgYSB1c2VyLg0KDQojIyBTdGVwIDU6IEFjdA0KDQpGcm9tIHRoZSBpbnNpZ2h0cyBkZXJpdmVkIGZyb20gdGhlIHNhbXBsZSBmaXRiaXQgZGF0YXNldHMsIEkgd291bGQgcmVjb21tZW5kIHRoZSBmb2xsb3dpbmcgdG8gdGhlIHN0YWtlaG9sZGVycyBpbiBvcmRlciB0byBib29zdCB0aGUgdXNlIG9mIEJlbGxhQmVhdCBhcHAgYW5kIGhvdyB0aGlzIGNhbiBib29zdCBtYXJrZXRpbmcgb2YgdGhlIHVzZSBvZiBMZWFmLCBUaW1lIGFuZCBTcHJpbmcuDQoNCjFcKSBJbmNyZWFzZSB0aGUgaW50ZW5zaXR5IG9mIG9ubGluZSBtYXJrZXR0aW5nIGZyb20gNiBhbSAtIDEwIGFtICwgMnBtIC0gM3BtLCBhbmQgOHBtIC0gMjNwbSBTY2hlZHVsaW5nIGFkdmVydHMgb24gbWVkaWEgY2hhbm5lbHMgZHVyaW5nIHRoZSBob3VycyB3aWxsIGhlbHAgdXNlcnMgdGhpbmsgb2YgdXNpbmcgQmVsbGFCZWF0IHByb2R1Y3RzIHdoZW4gdGhleSBhcmUgbW9yZSBhY3RpdmUuDQoNCjJcKSBJbnRyb2R1Y2Ugc3RlcCBub3RpZmljYXRpb25zIGluIHRoZSBCZWxsYUJlYXQgQXBwIHRvIG5vdGlmeSB1c2VycyBhdCAxMnBtLCAzcG0gYW5kIDlwbSBvZiB0aGVpciBzdGVwIGNvdW50LiBUaGlzIHdpbGwgaGVscCB1c2VycyBtb25pdG9yIHRoZWlyIHN0ZXAgY291bnQgYW5kIHBsYW4gdGhlaXIgZGFpbHkgYWN0aXZpdGllcw0KDQozXCkgSW50cm9kdWNlIHNsZWVwIG5vdGlmaWNhdGlvbiB0byBoZWxwIHVzZXJzIG5vdCB1c2UgdGhlaXIgcGhvbmVzIHdoZW4gdGhleSBhcmUgaW4gYmVkLiBUaGlzIHdpbGwgaGVscCB0aGVtIGdldCBhZGVxdWF0ZSBzbGVlcCBkdXJpbmcgdGhlIG5pZ2h0Lg0KDQo0XCkgSW5jcmVhc2UgbWFya2V0dGluZyBjYW1wYWlnbnMgdG8gdGFyZ2V0IGxpZ2h0IGFuZCBzZWRlbnRhcnkgdXNlcnMgYnkgYWR2ZXJ0aXNpbmcgaG93IEJlbGxhQmVhdCBjYW4gaGVscCB0aGVtIG1lZXQgdGhlaXIgZml0bmVzcyBnb2FscyBiYXNlZCBvbiBhY3Rpdml0eSBsb2dnZWQgYW5kIGhvdyBpdCBjb3JyZXNwb25kcyB0byBjYWxvcmllcyBidXJudC4NCg0KNVwpIEludHJvZHVjZSBhIHJld2FyZCBzeXN0ZW0gZm9yIHVzZXJzIHRvIGVuY291cmFnZSB1c2VycyB0byBsb2cgdGhlaXIgYWN0aXZpdHkgaW4gQmVsbGFCZWF0IEFwcC4gV2UgY2FuIGFsc28gaGVscCBpbnRyb2R1Y2UgdGhlbSB0byBvdGhlciBCZWxsYUJlYXQgcHJvZHVjdHMgdGhhdCB3aWxsIGF1dG9tYXRpY2FsbHkgbG9nIHRoZSBpbmZvcm1hdGlvbiBmb3IgdGhlbSB3aXRob3V0IHRoZSBuZWVkIG9mIG1hbnVhbGx5IGVudGVyaW5nIHRoZSBpbmZvcm1hdGlvbi4NCg==